﻿-- Author      : Kurapica
-- Create Date : 6/12/2008 1:12:25 AM

-- UIObject
do
	-- Check Version
	local version = 1
	if not IGAS:RegisterFile("IGAS.GUI.Widget.UIObject", version) then
		return
	end

    local getmetatable = getmetatable
    local pairs = pairs
    local ipairs = ipairs
    local type = type
    local error = error
	local next = next
    local CreateFrame = CreateFrame
	local getn = table.getn
    
	local _WidgetName = "UIObject"

	local _GUI = IGAS.GUI
	local _Widget = IGAS.GUI.Widget
    local _BaseFunc = IGAS.GUI.Base.Func
	local _PropertyType = IGAS.GUI.Base.PropertyType
		
	-- FuncProxy
	local _FuncProxy = {
        --- Original Functions
        -- GetAlpha() - Return this object's alpha (transparency) value. 
        ["GetAlpha"] = function(self)
            return self.__UI:GetAlpha()
        end,
        
        -- SetAlpha(alpha) - Set the object's alpha (transparency) value. 
        ["SetAlpha"] = function(self, alpha)
            self.__UI:SetAlpha(alpha)
        end,
    
        -- GetName() - Return the name of the object. 
        ["GetName"] = function(self)
            return self.__Name
        end,
        
        -- SetName(name) - Set the name of the object.
        ["SetName"] = function(self, name)
            if self.__Parent then
                if name == self.__Name then
                    return
                end
                
                if self.__Parent.__Childs and type(self.__Parent.__Childs) == "table" then
                    if self.__Parent.__Childs[name] then
                        error("this name is used.",2)
                    end
                    
                    if self.__Name then
                        self.__Parent.__Childs[self.__Name] = nil
                    end
                end
                
                if not (self.__Parent.__Childs and type(self.__Parent.__Childs) == "table") then
                    self.__Parent.__Childs = {}
                end
                self.__Parent.__Childs[name] = self
            end
            
            self.__Name = name
        end,
        
        -- GetObjectType() - Get the type of this object. 
        ["GetObjectType"] = function(self)
            return self.__ObjectType
        end,
        
        -- IsObjectType("type") - Determine if this object is of the specified type, or a subclass of that type. 
        ["IsObjectType"] = function(self, objType)
            if type(objType) == "string" then
                return self.__ObjectType == _Widget[objType]
            else
                return self.__ObjectType == objType
            end
        end,
        
        --- Special Functions        
		-- IsIGASWidget
		["IsIGASWidget"] = function(self)
			return true
		end,
		
	    -- Dispose, release resource
        ["Dispose"] = function(self)
            -- Call their childs' dispose method
            if self.__Childs and type(self.__Childs) == "table" then
				for _,ob in pairs(self.__Childs) do
                    if ob["IsIGASWidget"] then
                        if ob.NotDispose then
                            ob.__Parent = nil
                        else
                            ob:Dispose()
                        end
                    end
                end
			end
            
            self.__Childs = nil
            
            -- Remove self from parent
            if self.__Name and self.__Parent then                
                if self.__Parent.__Childs and type(self.__Parent.__Childs) == "table" then
                    self.__Parent.__Childs[self.__Name] = nil
                end
            end
            
            self.__Parent = nil
			
			-- Dipose self
			setmetatable(self, nil)
			self.__StackScripts = nil
        end,
        
		-- Fire func, used for personal script
		["Fire"] = function(self, sc, ...)
			local chk = false
			
			if not sc then return end
			
			if self.__StackScripts[sc] then
				for i = 1, getn(self.__StackScripts[sc]) do
					chk = self.__StackScripts[sc][i](self, ...)
					if chk then
						break
					end
				end
				
				if not chk and self.__StackScripts[sc][0] then
					self.__StackScripts[sc][0](self, ...)
				end
			elseif self[sc] and type(self[sc]) == "function" then
				self[sc](self, ...)
			end
		end,
        
        -- AddChild
        ["AddChild"] = function(self, ob)
            if ob and ob.__Name then
                -- Check
                if self.__Childs and type(self.__Childs) == "table" and self.__Childs[ob.__Name] then
                    if self.__Childs[ob.__Name] ~= ob then
                        error("There is a child with the same name")
                    else
                        return
                    end
                end
                
                -- Remove ob from it's old parent
                if ob.__Parent then
                    if not ob.__Parent:RemoveChild(ob) then
						error("Can't remove the child from it's old parent")
					end
                end
                
                -- Add ob to new parent
                if not(self.__Childs and type(self.__Childs) == "table") then
                    self.__Childs = {}
                end
                
                ob.__Parent = self
                self.__Childs[ob.__Name] = ob
				
				-- Only set parent to ui when the wrapper's objecttype is not a not-child.
				if _BaseFunc.GetUI(ob) ~= ob and _BaseFunc.GetUI(ob)["SetParent"] and (not ob.__ObjectType.NotChild) then
					_BaseFunc.GetUI(ob):SetParent(_BaseFunc.GetUI(self))
				end
            else
                error("can't add this child", 2)
            end
        end,
        
		-- HasChild
		["HasChilds"] = function(self)
			if self.__Childs and type(self.__Childs) == "table" and next(self.__Childs) then				
				return true
			else
				return false
			end
		end,
		
        -- GetChild
        ["GetChild"] = function(self, ob)
        	local _name
        	
        	if ob then
        		if type(ob) == "string" then
        			_name = ob
        		elseif ob["GetName"] then
        			_name = ob:GetName()
        		else
        			return nil
        		end
        		
        		if self.__Childs and type(self.__Childs) == "table" and self.__Childs[_name] then
                    if type(ob) == "table" and self.__Childs[_name] ~= ob then
                        return nil
                    end
        			return self.__Childs[_name]
        		else
        			return nil
        		end
        	else
        		return nil
        	end
        end,
        
        -- RemoveChild
        ["RemoveChild"] = function(self, ob)
			local child = nil
			
            if ob then
                if type(ob) == "string" then
                    if self.__Childs and type(self.__Childs) == "table" and  self.__Childs[ob] then
						child = self.__Childs[ob]
                    end
                elseif ob.__Name then
                    if self.__Childs and type(self.__Childs) == "table" and self.__Childs[ob.__Name] == ob then
						child = ob
                    end
                end
            end
			
			if child then
				-- if child's ObjectType is not-child. Don't set parent to nil, because it has a another parent, only remove parent when dispose
				if _BaseFunc.GetUI(child) ~= child and _BaseFunc.GetUI(child)["SetParent"] and (not child.__ObjectType.NotChild) then
					_BaseFunc.GetUI(child):SetParent(nil)
				end
				
				child.__Parent = nil
				self.__Childs[child.__Name] = nil
				
				return true
			end
			
			return false
        end,
		
		-- CallMethod
		["CallMethod"] = function(self, superType, method, ...)
			return _BaseFunc.CallMethod(superType, method, self, ...)
		end,		
	}
    
	-- Property
	local _Property = {
		--- Alpha
		["Alpha"] = {
			["Set"] = function(self, alpha)
				self:SetAlpha(alpha)
			end,

			["Get"] = function(self)
				return self:GetAlpha()
			end,

			["Type"] = _PropertyType.Alpha,
		},

		--- Name
		["Name"] = {
			["Set"] = function(self, name)
				self:SetName(name)
			end,
            
			["Get"] = function(self)
				return self:GetName()
			end,

			["Type"] = _PropertyType.String,
		},
        
        -- NotDispose
        ["NotDispose"] = {
			["Set"] = function(self, flag)
				self.__NotDispose = (flag and true) or nil
			end,
            
			["Get"] = function(self)
				return (self.__NotDispose and true) or false
			end,

			["Type"] = _PropertyType.Boolean,
		},
        
        -- InDesignMode
        ["InDesignMode"] = {
            ["Get"] = function(self)
				return (self.__InDesignMode and true) or false
			end,
			["Type"] = _PropertyType.Boolean,
        },
	}
    
    local _WidgetInfo = {
        ["WidgetName"] = _WidgetName,
        ["FuncProxy"] = _FuncProxy,
        ["Property"] = _Property,
    }
    
    _Widget[_WidgetName] = _GUI.NewWidget(_WidgetInfo)
end